/**
 * Created by tdzl2003 on 8/25/16.
 */

import {EventEmitter} from 'fbemitter';
import URI from 'urijs';
import filterObject from 'fbjs/lib/filterObject';

class ResponseError extends Error {
  constructor(message, code, origin) {
    super(message);
    this.code = code;
    this.origin = origin;
  }
}

const RPC = new EventEmitter;
export default RPC;
const emit = RPC.emit.bind(RPC);

const KEY_TOKEN = 'accessToken';
const UPLOAD_TOKEN_URL = 'upload';

let token = null;

export function getToken() {
  return token;
}

export function saveToken(_token) {
  token = _token;
  sessionStorage.setItem(KEY_TOKEN, token);
}

export function loadToken() {
  token = sessionStorage.getItem(KEY_TOKEN);
  return token;
}

export function clearToken() {
  sessionStorage.removeItem(KEY_TOKEN);
  token = null;
}

export function emitLogout() {
  emit('invalidToken');
}

async function request(uri, _options) {
  const options = _options || {};
  options.method = options.method || 'GET';
  options.headers = options.headers || {};

  if (token) {
    options.headers['x-accesstoken'] = token;
  }

  if (__DEV__) {
    console.log(`${options.method} ${uri}`);
    if (options.body) {
      console.log(options.body);
    }
  }

  const resp = await fetch(uri.toString(), options);
  const text = await resp.text();
  if (__DEV__) {
    console.log('RESP:', text);
  }
  const json = JSON.parse(text);

  // 如果请求失败
  if (resp.status !== 200) {
    if (resp.status === 401) {
      // HTTP 401 表示授权验证失败(通常是token已过期)
      emit('invalidToken');
    }

    throw new ResponseError(json.message, resp.status, json);
  }

  return json;
}

export function get(url, data, options) {
  const uri = new URI(url);
  if (data) {
    uri.query(filterObject(data, v=>v));
  }

  return request(uri, options);
}

export function post(url, data, options) {
  return request(new URI(url), {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(data),
    ...options,
  });
}

export function put(url, data, options) {
  return request(new URI(url), {
    method: 'PUT',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(data),
    ...options,
  });
}

export function $delete(url, data, options) {
  return request(new URI(url), {
    method: 'DELETE',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(data),
    ...options,
  });
}
